package com.hfb.mashibing.alip8.juc.c020_01_interview.ABCABC;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 *  互联网一线大厂面试题：
 *      徒手写出：3个不同的线程，交替输出ABCABCABC。。。
 *
 * 线程排序问题
 *  思路：
 *      利用 ReentrantLock 的3个条件队列，隔离ABC，分别依次唤醒、阻塞ABC
 *      再用2个门闩（B、C）保证首次运行的顺序必须是线程ABC，才能保证结果
 *
 */
public class Test {

    private static ReentrantLock lock = new ReentrantLock();
    private static Condition cA = lock.newCondition();
    private static Condition cB = lock.newCondition();
    private static Condition cC = lock.newCondition();

    private static CountDownLatch latchB = new CountDownLatch(1);
    private static CountDownLatch latchC = new CountDownLatch(1);


    public static void main(String[] args) {
        // 思路：3个线程，3个不同的队列（Condition），A唤醒B，B唤醒C
        Thread threadA = new Thread(()->{
           lock.lock();
           // 先输出A，然后唤醒B
           try {
               for (int i = 0; i < 10; i++) {
                   System.out.print("A");
                   cB.signal(); // 唤醒B
                   if (i == 0)
                       latchB.countDown();
                   cA.await(); // 阻塞A
               }
               cB.signal(); // 唤醒B
           } catch (Exception e) {
               e.printStackTrace();
           } finally {
               lock.unlock();
           }

        }, "Thread-A");

        Thread threadB = new Thread(()->{
           // 先等待唤醒
           try {
               latchB.await();
           } catch (InterruptedException e) {
               e.printStackTrace();
           }

           lock.lock();
           try {
               for (int i = 0; i < 10; i++) {
                   System.out.print("B");
                   cC.signal(); // 唤醒C
                   if (i == 0)
                       latchC.countDown();
                   cB.await(); // 阻塞B
               }
               cC.signal(); // 唤醒C
           } catch (Exception e) {
               e.printStackTrace();
           } finally {
               lock.unlock();
           }
        }, "Thread-B");


        Thread threadC = new Thread(()->{
           // 先等待唤醒
           try {
               latchC.await();
           } catch (InterruptedException e) {
               e.printStackTrace();
           }

           lock.lock();
           try {
               for (int i = 0; i < 10; i++) {
                   System.out.print("C");
                   cA.signal(); // 唤醒A
                   cC.await(); // 阻塞C
               }
               cA.signal(); // 唤醒A
               System.out.println();
           } catch (Exception e) {
               e.printStackTrace();
           } finally {
               lock.unlock();
           }
        }, "Thread-C");

        threadA.start();
        threadB.start();
        threadC.start();
    }
}
